﻿using System;
using System.Threading;

namespace Epic.Core
{
    /// <summary>
    /// 提供一个线程安全的可消解对象基类。
    /// </summary>
    public abstract class DisposableBase
        : IDisposable
    {
        private volatile bool mIsDisposeCalled = false;
        /// <summary>
        /// Determine if the Dispose method is explicitly called.
        /// </summary>
        protected bool IsDisposeCalled { get { return mIsDisposeCalled; } }

        private volatile int mIsDisposeTriggered = 0;
        /// <summary>
        /// Determine if the disposing process is triggered by any means.
        /// </summary>
        protected bool IsDisposeTriggered { get { return mIsDisposeTriggered != 0; } }

        private volatile bool mIsDisposed = false;
        /// <summary>
        /// Determine if the object is already disposed.
        /// </summary>
        public bool IsDisposed { get { return mIsDisposed; } }

        /// <summary>
        /// The method which implements the actual disposing logic.
        /// </summary>
        protected abstract void Dispose(bool disposing);

        private void DoDispose(bool disposing)
        {
            if (disposing)
                mIsDisposeCalled = true;

#pragma warning disable 0420
            if (Interlocked.Exchange(ref mIsDisposeTriggered, 1) != 0)
                return;
#pragma warning restore 0420

            Dispose(disposing);

            mIsDisposed = true;

            if (disposing)
            {
                GC.SuppressFinalize(this);
            }
        }

        public void Dispose()
        {
            DoDispose(true);
        }

#pragma warning disable 1591
        ~DisposableBase()
        {
            DoDispose(false);
        }
    }

    public class ActionDisposable
        : DisposableBase
    {
        private Action<bool> mDisposeAction;
        public ActionDisposable(Action<bool> disposeAction)
        {
            mDisposeAction = disposeAction;
        }
        protected override void Dispose(bool disposing)
        {
            if (mDisposeAction != null)
                mDisposeAction(disposing);
        }
    }

    public class EventDisposable
        : DisposableBase
    {
        public event CommandEventHandler<bool> DisposeCalled;
        protected override void Dispose(bool disposing)
        {
            var eventHandler = DisposeCalled;
            if (eventHandler != null)
                eventHandler(this, new CommandEventArgs<bool>(disposing));
        }
    }
}
